using System.Collections.Generic;
using System.Linq;

namespace LS
{
    public class DoubleKeyMap<TKey1, TKey2, TValue>
    {
        protected Dictionary<TKey1, TValue> m_Key1VMap;
        protected Dictionary<TKey2, TValue> m_Key2VMap;
        protected Dictionary<TValue, TKey1> m_VKey1Map;
        protected Dictionary<TValue, TKey2> m_VKey2Map;

        private bool m_DoubleWay = false;

        /// <summary>
        /// 是否支持双向映射,双向映射时可通过value反向获取其key值
        /// </summary>
        public bool IsDoubleWayMap
        {
            get
            {
                return m_DoubleWay;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="doubleWay">双向映射</param>
        public DoubleKeyMap(bool doubleWay = false)
        {
            m_DoubleWay = doubleWay;

            m_Key1VMap = new Dictionary<TKey1, TValue>();
            m_Key2VMap = new Dictionary<TKey2, TValue>();

            if (doubleWay)
            {
                m_VKey1Map = new Dictionary<TValue, TKey1>();
                m_VKey2Map = new Dictionary<TValue, TKey2>();
            }
        }

        public bool ContainsKey(TKey1 key)
        {
            return m_Key1VMap.ContainsKey(key);
        }

        public bool ContainsKey(TKey2 key)
        {
            return m_Key2VMap.ContainsKey(key);
        }

        public bool ContainsValue(TValue value)
        {
            return m_Key1VMap.ContainsValue(value);
        }

        /// <summary>
        /// 设置键值映射
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value1">值</param>
        public void Set(TKey1 key, TValue value)
        {
            m_Key1VMap[key] = value;

            if (!m_DoubleWay)
                return;

            if (m_Key1VMap.TryGetValue(key, out TValue previous))
            {
                m_VKey1Map.Remove(previous);
            }
            m_VKey1Map[value] = key;
        }

        /// <summary>
        /// 设置键值映射
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="value1">值</param>
        public void Set(TKey2 key, TValue value)
        {
            m_Key2VMap[key] = value;

            if (!m_DoubleWay)
                return;

            if (m_Key2VMap.TryGetValue(key, out TValue previous))
            {
                m_VKey2Map.Remove(previous);
            }

            m_VKey2Map[value] = key;
        }

        public void Set(TKey1 key1,TKey2 key2, TValue value)
        {
            this.Set(key1, value);
            this.Set(key2, value);
        }

        /// <summary>
        /// 移除键值映射
        /// </summary>
        /// <param name="key"></param>
        public void Remove(TKey1 key)
        {
            if (m_DoubleWay)
            {
                if (m_Key1VMap.TryGetValue(key, out TValue previous))
                {
                    m_VKey1Map.Remove(previous);
                }
            }
            m_Key1VMap.Remove(key);
        }

        /// <summary>
        /// 移除键值映射
        /// </summary>
        /// <param name="key"></param>
        public void Remove(TKey2 key)
        {
            if (m_DoubleWay)
            {
                if (m_Key2VMap.TryGetValue(key, out TValue previous))
                {
                    m_VKey2Map.Remove(previous);
                }
            }
            m_Key2VMap.Remove(key);
        }

        public void Remove(TKey1 key1, TKey2 key2)
        {
            Remove(key1);
            Remove(key2);
        }

        /// <summary>
        /// 获取值
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public TValue GetValue(TKey1 key)
        {
            if (m_Key1VMap.TryGetValue(key, out var value))
            {
                return value;
            }
            return default;
        }

        /// <summary>
        /// 获取值
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public TValue GetValue(TKey2 key)
        {
            if (m_Key2VMap.TryGetValue(key, out var value))
            {
                return value;
            }
            return default;
        }

        /// <summary>
        /// 通过值获取键，只能在IsDoubleWayMap为True时使用
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public TKey1 GetKey1(TValue value)
        {
            if (!m_DoubleWay)
            {
                throw new System.Exception("This function is only used in DoubleWay mode");
            }

            if (m_VKey1Map.TryGetValue(value, out var k))
            {
                return k;
            }

            return default;
        }

        /// <summary>
        /// 通过值获取键，只能在IsDoubleWayMap为True时使用
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public TKey2 GetKey2(TValue value)
        {
            if (!m_DoubleWay)
            {
                throw new System.Exception("This function is only used in DoubleWay mode");
            }

            if (m_VKey2Map.TryGetValue(value, out var key))
            {
                return key;
            }

            return default;
        }

        public bool TryGetValue(TKey1 key, out TValue value)
        {
            return m_Key1VMap.TryGetValue(key, out value);
        }

        public bool TryGetValue(TKey2 key, out TValue value)
        {
            return m_Key2VMap.TryGetValue(key, out value);
        }

        public bool TryGetKey1(TValue value, out TKey1 key)
        {
            if (!m_DoubleWay)
            {
                key = default;
                return false;
            }
            return m_VKey1Map.TryGetValue(value, out key);
        }

        public bool TryGetKey2(TValue value, out TKey2 key)
        {
            if (!m_DoubleWay)
            {
                key = default;
                return false;
            }
            return m_VKey2Map.TryGetValue(value, out key);
        }

        public TKey1[] GetAllKey1s()
        {
            return m_Key1VMap.Keys.ToArray();
        }

        public TKey2[] GetAllKey2s()
        {
            return m_Key2VMap.Keys.ToArray();
        }


        public TValue[] GetAllValues()
        {
            return m_Key1VMap.Values.ToArray();
        }

        /// <summary>
        /// 清除全部映射
        /// </summary>
        public void Clear()
        {
            m_Key1VMap?.Clear();
            m_Key2VMap?.Clear();
            m_VKey1Map?.Clear();
            m_VKey2Map?.Clear();
        }
    }
}
